package com.xuecheng.comment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.comment.model.*;
import com.xuecheng.api.comment.model.dto.CommentDTO;
import com.xuecheng.api.comment.model.dto.ReplyDTO;
import com.xuecheng.api.content.model.dto.CoursePubDTO;
import com.xuecheng.api.learning.model.dto.UserDTO;
import com.xuecheng.comment.agent.CoursePubApiAgent;
import com.xuecheng.comment.agent.LearningApiAgent;
import com.xuecheng.comment.common.constant.CommentErrorCode;
import com.xuecheng.comment.convert.CommentConvert;
import com.xuecheng.comment.convert.ReplyConvert;
import com.xuecheng.comment.entity.Comment;
import com.xuecheng.comment.entity.Reply;
import com.xuecheng.comment.mapper.CommentMapper;
import com.xuecheng.comment.mapper.ReplyMapper;
import com.xuecheng.comment.service.CommentService;
import com.xuecheng.comment.service.ReplyService;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.common.USEEnum;
import com.xuecheng.common.enums.content.TargetTypeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private LearningApiAgent learningApiAgent;

    @Autowired
    private CoursePubApiAgent coursePubApiAgent;

    @Autowired
    private ReplyService replyService;

    @Autowired
    private ReplyMapper replyMapper;


    /**
     * 课程列表查询
     *
     * @param model
     * @return
     */
    @Override
    public PageVO<CommentDTO> querryCommentList(QuerryCommentModel model, String useflag) {

        // 1.业务传入参数的判断
        Long pageNo = model.getPageNo();
        Integer pageSize = model.getPageSize();
        // 2.构建分页查询
        if (ObjectUtils.isEmpty(pageNo) || pageNo < 1) {
            pageNo = PageRequestParams.DEFAULT_PAGE_NUM;
        }
        if (ObjectUtils.isEmpty(pageSize) || pageSize < 1) {
            pageSize = PageRequestParams.DEFAULT_PAGE_SIZE;
        }
        Page<Comment> page = new Page<>(pageNo, pageSize);

        // 3.构建条件查询
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();

        //3.1判断，如果是门户查询，则添加 查询条件，根据课程发布id查询
        if (useflag.equals(USEEnum.USE_PORTAL.getCode())) {
            //查询条件，对象Id（课程发布Id）
            if (StringUtil.isBlank(model.getTargetId().toString())) {
                ExceptionCast.cast(CommentErrorCode.E_130105);
            }
            Long targetId = Long.valueOf(model.getTargetId());
            queryWrapper.eq(Comment::getTargetId, targetId);
            //查询条件：课程发布对象 名称
            queryWrapper.eq(!ObjectUtils.isEmpty(model.getTargetName()), Comment::getTargetName, model.getTargetName());
        }

        //3.2判断，如果是教育机构查询
        if (useflag.equals(USEEnum.USE_ORGANI.getCode())) {
            Long companyId = model.getCompanyId();
            if (ObjectUtils.isEmpty(companyId)) {
                ExceptionCast.cast(CommonErrorCode.E_110006);
            }

            //构建like查询
            if (StringUtil.isNotBlank(model.getTargetName())) {
                queryWrapper.like(Comment::getComeFrom, model.getTargetName());
            }
            //获取该教育机构所有已发布课程 id 集合
            RestResponse<List<CoursePubDTO>> restResponse = coursePubApiAgent.getCoursePubByCompanyId(companyId);
            if (!restResponse.isSuccessful()) {
                ExceptionCast.cast(CommonErrorCode.E_999981);
            }
            List<CoursePubDTO> list = restResponse.getResult();
            if (ObjectUtils.isEmpty(list)) {
                //list为空，代表该机构未发布课程，未发布，则直接返回 空集合
                list = new ArrayList<>();
                return new PageVO<>();
            } else {
                //list不为空，代表该教育机构 已发布了课程
                List<Long> coursePubIds = list.stream().map(CoursePubDTO::getId).collect(Collectors.toList());
                queryWrapper.in(Comment::getTargetId, coursePubIds);
            }
        }
        //3.3判断，如果是运营后台查询，无需额外设置查询条件,  查询所有评论及其回复
        queryWrapper.eq(Comment::getStatus, CommonEnum.USING_FLAG.getCode());

        //3.4 构建查询条件：依据 好评，中评，差评

        Integer level = model.getLevel();
        if (!ObjectUtils.isEmpty(level)) {
            switch (level) {
                case 1:
                    queryWrapper.gt(Comment::getStarRank, 3);
                    break;
                case 0:
                    queryWrapper.eq(Comment::getStarRank, 3);
                    break;
                case -1:
                    queryWrapper.lt(Comment::getStarRank, 3);
                    break;
                default:
                    break;
            }
        }

        // 4.查询
        Page<Comment> pageResult = this.page(page, queryWrapper);
        List<Comment> comments = pageResult.getRecords();

        // 5.封装CommentDTO
        List<CommentDTO> commentDTOS = Collections.emptyList();
        if (ObjectUtils.isEmpty(comments)) {
            //如果评论为空，则直接返回空页面
            return new PageVO<>();
        }
        //使用mapStruct转换对象
        commentDTOS = CommentConvert.INSTANCE.entitys2dtos(comments);

        //6.封装评论回复
        //6.1查询回复
        ArrayList<Long> CommentIds = new ArrayList();
        for (CommentDTO commentDTO : commentDTOS) {
            CommentIds.add(commentDTO.getCommentId());
        }
        LambdaQueryWrapper<Reply> replyWrapper = new LambdaQueryWrapper<>();

        if (CommentIds.size() > 1) {
            replyWrapper.in(Reply::getCommentId, CommentIds);
        } else {
            replyWrapper.eq(Reply::getCommentId, CommentIds.get(0));
        }

        Page<Reply> replyPage = new Page<>(pageNo, pageSize);

        Page<Reply> replyPageResult = replyService.page(replyPage, replyWrapper);
        List<Reply> replys = replyPageResult.getRecords();

        // 6.2封装ReplyDTO
        List<ReplyDTO> replyDTOS = Collections.emptyList();
        if (!ObjectUtils.isEmpty(replys)) {
            //使用mapStruct转换对象
            replyDTOS = ReplyConvert.INSTANCE.entitys2dtos(replys);
            for (CommentDTO commentDTO : commentDTOS) {
                ArrayList<ReplyDTO> replyDtoList = new ArrayList<>();
                for (ReplyDTO replyDTO : replyDTOS) {
                    if (replyDTO.getCommentId().equals(commentDTO.getCommentId())) {
                        replyDtoList.add(replyDTO);
                    }
                }
                commentDTO.setReplyDTOList(replyDtoList);
            }
        }
        PageVO<CommentDTO> pageVO = new PageVO(commentDTOS, page.getTotal(), pageNo, pageSize);

        return pageVO;
    }

    /**
     * 添加课程评论
     * <p>
     * 1、校验数据
     * 2、构建课程评论对象，赋值
     * 3、转换dto返回
     *
     * @param model
     * @return
     */
    @Override
    @Transactional
    public CommentDTO createComment(CommentModel model) {

        //1、校验数据
        if (StringUtil.isBlank(model.getStarRank().toString()) || StringUtil.isBlank(model.getTargetId().toString())) {
            ExceptionCast.cast(CommentErrorCode.E_130103);
        }

        //2、构建课程评论对象，赋值
        Comment comment = new Comment();

        //将model的传参值赋给 comment
        if (StringUtil.isNotBlank(model.getCommentText())) {
            comment.setCommentText(model.getCommentText());
        }
        comment.setStarRank(model.getStarRank());

        comment.setTargetId(Long.valueOf(model.getTargetId()));

        //将查询到的相关数据赋值给comment

        //2.1 设置用户信息
        RestResponse<UserDTO> userDtoResponse = learningApiAgent.getUserByUserName(model.getLoginUser().getUsername());
        if (!userDtoResponse.isSuccessful()) {
            ExceptionCast.cast(CommentErrorCode.E_140100);
        }

        UserDTO userDto = userDtoResponse.getResult();

        //2.2根据用户名 查询是否 已经评论过,如果已经评论过，则不允许评论
        LambdaQueryWrapper<Comment> querryWrapper = new LambdaQueryWrapper<>();
        querryWrapper.eq(Comment::getUserName, userDto.getName());
        int count1 = this.count(querryWrapper);
        if (count1 > 0) {
            //已经评论过
            ExceptionCast.cast(CommentErrorCode.E_130102);
        }

        comment.setUserId(userDto.getUserId());
        if (StringUtil.isNotBlank(userDto.getUserpic())) {
            comment.setUserHead(userDto.getUserpic());
        }
        if (StringUtil.isNotBlank(userDto.getName())) {
            comment.setNickName(userDto.getName());
        }
        comment.setUserName(userDto.getUsername());

        //2.2 TODO 点赞数量，用redis操作
        comment.setPraiseNum(999);

        //2.3设置常规数据
        comment.setId(null);
        comment.setForbidReply(0);

        //2.4评论对象数据
        RestResponse<CoursePubDTO> coursePubDtoResponse = coursePubApiAgent.getCoursePubById(Long.valueOf(model.getTargetId()));
        if (!coursePubDtoResponse.isSuccessful()) {
            ExceptionCast.cast(CommonErrorCode.E_100106);
        }
        CoursePubDTO coursePubDto = coursePubDtoResponse.getResult();
        comment.setTargetName(coursePubDto.getName());
        comment.setTargetType(TargetTypeEnum.TARGET_TYPE_COURSE.getDesc());

        //2.5 设置company数据
        Long companyId = coursePubDto.getCompanyId();
        if (StringUtil.isNotBlank(companyId.toString())) {
            comment.setBelongTo(Long.valueOf(companyId));
        }
        String companyName = coursePubDto.getCompanyName();
        if (StringUtil.isNotBlank(companyName)) {
            comment.setComeFrom(companyName);
        } else {
            comment.setComeFrom("companyName");
        }
        comment.setReplyStatus(Integer.valueOf(CommonEnum.USING_FLAG.getCode()));
        //操作数据库,添加评论
        int count = commentMapper.insert(comment);
        if (count == 0) {
            ExceptionCast.cast(CommentErrorCode.E_130101);
        }

        CommentDTO commentDTO = CommentConvert.INSTANCE.entity2dto(comment);

        return commentDTO;
    }

    //课程评论点赞
    @Transactional
    @Override
    public Boolean praiseComment(Long commentId, String userName) {

        Comment comment = this.getById(commentId);

        if (ObjectUtils.isEmpty(comment)) {
            ExceptionCast.cast(CommonErrorCode.E_100109);
        }
        Boolean praiseResult = commentMapper.praiseComment(commentId);
        if (praiseResult) {
            ExceptionCast.cast(CommentErrorCode.E_130106);
        }

//        Integer count = comment.getPraiseNum();
//
//        Integer praise = count++;
//
//        LambdaUpdateWrapper<Comment> wrapper = new LambdaUpdateWrapper<>();
//
//        wrapper.set(Comment::getPraiseNum,praise);
//        wrapper.set(Comment::getUserName,userName);

//        boolean update = this.update(wrapper);
        return praiseResult;
    }

    //课程统计数据
    @Override
    public CommentStaticsModel commentStatistics(Long targetId) {

        if (StringUtil.isBlank(targetId.toString())) {
            ExceptionCast.cast(CommonErrorCode.E_100116);
        }
        CommentStaticsModel staticsModel = new CommentStaticsModel();
        //5星
        LambdaQueryWrapper<Comment> querywrapper5 = new LambdaQueryWrapper<>();
        querywrapper5.eq(Comment::getStarRank, 5);
        int count5 = this.count(querywrapper5);
        staticsModel.setStarRank5Nums(count5);

        //4星
        LambdaQueryWrapper<Comment> querywrapper4 = new LambdaQueryWrapper<>();
        querywrapper4.eq(Comment::getStarRank, 4);
        int count4 = this.count(querywrapper4);
        staticsModel.setStarRank4Nums(count4);

        //3星
        LambdaQueryWrapper<Comment> querywrapper3 = new LambdaQueryWrapper<>();
        querywrapper3.eq(Comment::getStarRank, 3);
        int count3 = this.count(querywrapper3);
        staticsModel.setStarRank3Nums(count3);

        //2星
        LambdaQueryWrapper<Comment> querywrapper2 = new LambdaQueryWrapper<>();
        querywrapper2.eq(Comment::getStarRank, 2);
        int count2 = this.count(querywrapper2);
        staticsModel.setStarRank2Nums(count2);

        //1星
        LambdaQueryWrapper<Comment> querywrapper1 = new LambdaQueryWrapper<>();
        querywrapper1.eq(Comment::getStarRank, 1);
        int count1 = this.count(querywrapper1);
        staticsModel.setStarRank1Nums(count1);

        int totalStar = count1 + count2 + count3 + count4 + count5;

        float avgStar = (float) totalStar / (float) 5;

        staticsModel.setTotalCommentNums(totalStar);
        staticsModel.setStarRank(String.valueOf(avgStar));
        staticsModel.setTargetId(Integer.valueOf(targetId.toString()));

        return staticsModel;
    }

    //评论回复
    @Transactional
    @Override
    public ReplyDTO commentReply(ReplyModel model) {
        if (ObjectUtils.isEmpty(model)) {
            ExceptionCast.cast(CommentErrorCode.E_130107);
        }
        Comment comment = this.getById(model.getCommentId());

        Integer status = comment.getReplyStatus();
        String sta = status.toString();
        if (CommonEnum.USING_FLAG.getCode() == sta) {
            ExceptionCast.cast(CommentErrorCode.E_130104);
        }
        //开始添加回复评论
        Reply reply = new Reply();
        reply.setCommentId(model.getCommentId().longValue());
        reply.setParentId(comment.getTargetId());
        reply.setUserName(comment.getUserName());
        reply.setReplyText(model.getReplyText());

        int insertResult = replyMapper.insert(reply);

        if (insertResult == 0) {
            ExceptionCast.cast(CommentErrorCode.E_130108);
        }

        Reply replyVo = replyService.getById(reply.getId());

        ReplyDTO replyDTO = ReplyConvert.INSTANCE.entity2dto(replyVo);

        return replyDTO;
    }

    //删除评论
    @Transactional
    @Override
    public Boolean deleteCommentById(Long commentId) {
        //        1.判断关键数据
        if (ObjectUtils.isEmpty(commentId)) {
            ExceptionCast.cast(CommentErrorCode.E_130103);
        }

//        2.查询评论信息并判断
        Comment comment = this.getById(commentId);
        if (ObjectUtils.isEmpty(comment) ||
                Comment.COMMENT_STATUS_WITHOUT.equals(comment.getStatus())) {
            ExceptionCast.cast(CommentErrorCode.E_130203);
        }

//        判断是否有回复评论
        if (Comment.COMMENT_STATUS_EXIST.equals(comment.getReplyStatus())) {
//            如果有，删除回复评论
            LambdaQueryWrapper<Reply> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Reply::getCommentId, commentId);
            List<Reply> replyComment = replyMapper.selectList(queryWrapper);
            if (CollectionUtils.isEmpty(replyComment)) {
                ExceptionCast.cast(CommentErrorCode.E_130203);
            }
            for (Reply reply : replyComment) {
                Long replyId = reply.getId();
                LambdaUpdateWrapper<Reply> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(Reply::getCommentId, comment.getId());
                updateWrapper.set(Reply::getStatus, Comment.COMMENT_STATUS_WITHOUT);
                int update = replyMapper.update(reply, updateWrapper);
                if (Comment.COMMENT_STATUS_EXIST != update) {
                    ExceptionCast.castWithExceptionMsg(CommentErrorCode.E_130104, "replyId : " + replyId);
                }
            }

        }

//       3.删除评论
        LambdaUpdateWrapper<Comment> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Comment::getId, commentId);
        updateWrapper.set(Comment::getStatus, Comment.COMMENT_STATUS_WITHOUT);
        boolean result = this.update(updateWrapper);

        if (!result) {
            ExceptionCast.cast(CommentErrorCode.E_130104);
        }

        return true;
    }

    //评论删除评论
    @Transactional
    @Override
    public Boolean deleteComments(String[] commentIds) {
        if (ObjectUtils.isEmpty(commentIds)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        LambdaUpdateWrapper<Comment> wrapper = new LambdaUpdateWrapper<>();
        List<String> commentIdList = Arrays.asList(commentIds);
        wrapper.in(Comment::getId, commentIdList);
        wrapper.set(Comment::getStatus, CommonEnum.DELETE_FLAG.getCode());
        boolean result = this.update(wrapper);
        return result;
    }

}